package net.guerlab.smart.wx.web.controller.user;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import net.guerlab.commons.collection.CollectionUtil;
import net.guerlab.commons.exception.ApplicationException;
import net.guerlab.smart.platform.commons.util.BeanConvertUtils;
import net.guerlab.smart.platform.excel.ExcelUtils;
import net.guerlab.smart.platform.server.controller.BaseFindController;
import net.guerlab.smart.platform.user.api.OperationLogApi;
import net.guerlab.smart.platform.user.auth.UserContextHandler;
import net.guerlab.smart.wx.core.domain.UserTagDTO;
import net.guerlab.smart.wx.core.domain.WxUserDTO;
import net.guerlab.smart.wx.core.exception.WxUserInvalidException;
import net.guerlab.smart.wx.core.searchparams.UserTagSearchParams;
import net.guerlab.smart.wx.core.searchparams.WxUserSearchParams;
import net.guerlab.smart.wx.service.entity.UserTag;
import net.guerlab.smart.wx.service.entity.UserTagMapping;
import net.guerlab.smart.wx.service.entity.WxUser;
import net.guerlab.smart.wx.service.searchparams.UserTagMappingSearchParams;
import net.guerlab.smart.wx.service.service.UserTagMappingService;
import net.guerlab.smart.wx.service.service.UserTagService;
import net.guerlab.smart.wx.service.service.WxUserService;
import net.guerlab.smart.wx.web.domain.SetTagRequestDTO;
import net.guerlab.smart.wx.web.excel.WxUserExcelExport;
import net.guerlab.web.result.ListObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 微信用户
 *
 * @author guer
 */
@Api(tags = "微信用户")
@RestController("/user/wxUser")
@RequestMapping("/user/wxUser")
public class WxUserController extends BaseFindController<WxUserDTO, WxUser, WxUserService, WxUserSearchParams, String> {

    private UserTagService tagService;

    private UserTagMappingService tagMappingService;

    private OperationLogApi operationLogApi;

    @Override
    protected ApplicationException nullPointException() {
        return new WxUserInvalidException();
    }

    @Override
    public WxUserDTO findOne(String id) {
        WxUserDTO dto = super.findOne(id);

        UserTagMappingSearchParams mappingSearchParams = new UserTagMappingSearchParams();
        mappingSearchParams.setOpenId(dto.getOpenId());

        Collection<Long> tagIds = CollectionUtil
                .toList(tagMappingService.selectAll(mappingSearchParams), UserTagMapping::getTagId);

        dto.setTagIds(tagIds);

        if (!tagIds.isEmpty()) {
            UserTagSearchParams tagSearchParams = new UserTagSearchParams();
            tagSearchParams.setTagIds(tagIds);

            dto.setTags(BeanConvertUtils.toList(tagService.selectAll(tagSearchParams)));
        }

        return dto;
    }

    @Override
    public ListObject<WxUserDTO> findList(WxUserSearchParams searchParams) {
        ListObject<WxUserDTO> result = BeanConvertUtils.toListObject(getService().queryPage(searchParams));
        Boolean queryTags = searchParams.getQueryTags();
        if (queryTags != null && queryTags) {
            fillTag(result.getList());
        }
        return result;
    }

    @Override
    public List<WxUserDTO> findAll(WxUserSearchParams searchParams) {
        List<WxUserDTO> result = BeanConvertUtils.toList(getService().queryAll(searchParams));
        Boolean queryTags = searchParams.getQueryTags();
        if (queryTags != null && queryTags) {
            fillTag(result);
        }
        return result;
    }

    @ApiOperation("根据openId列表查询用户列表")
    @PostMapping("/findMap")
    public Map<String, WxUserDTO> findMap(@RequestBody Collection<String> openIds) {
        if (openIds == null || openIds.isEmpty()) {
            return Collections.emptyMap();
        }

        WxUserSearchParams searchParams = new WxUserSearchParams();
        searchParams.setOpenIds(openIds);

        Collection<WxUser> wxUsers = service.selectAll(searchParams);

        Map<String, WxUserDTO> result = CollectionUtil.toMap(wxUsers, WxUser::getOpenId, WxUser::toDTO);
        fillTag(result.values());
        return result;
    }

    @ApiOperation("查询用户数量")
    @GetMapping("/count")
    public int findCount(WxUserSearchParams searchParams) {
        return service.selectCount(searchParams);
    }

    private void fillTag(Collection<WxUserDTO> users) {
        Map<String, WxUserDTO> userMap = CollectionUtil.toMap(users, WxUserDTO::getOpenId);

        UserTagMappingSearchParams mappingSearchParams = new UserTagMappingSearchParams();
        mappingSearchParams.setOpenIds(userMap.keySet());

        Collection<UserTagMapping> mappings = tagMappingService.selectAll(mappingSearchParams);

        Collection<Long> tagIds = CollectionUtil.toList(mappings, UserTagMapping::getTagId);

        Map<Long, UserTagDTO> tagMap;

        if (!tagIds.isEmpty()) {
            UserTagSearchParams tagSearchParams = new UserTagSearchParams();
            tagSearchParams.setTagIds(tagIds);

            tagMap = CollectionUtil.toMap(tagService.selectAll(tagSearchParams), UserTag::getTagId, UserTag::toDTO);
        } else {
            tagMap = Collections.emptyMap();
        }

        if (tagMap.isEmpty()) {
            return;
        }

        Map<String, List<UserTagMapping>> userTagMappingMap = CollectionUtil.group(mappings, UserTagMapping::getOpenId);

        userTagMappingMap.forEach((openId, userTagMapping) -> {
            WxUserDTO user = userMap.get(openId);

            if (user != null) {
                Collection<UserTagDTO> userTags = userTagMapping.stream().map(UserTagMapping::getTagId).map(tagMap::get)
                        .filter(Objects::nonNull).collect(Collectors.toList());

                user.setTags(userTags);
                user.setTagIds(CollectionUtil.toList(userTags, UserTagDTO::getTagId));
            }
        });
    }

    @ApiOperation("删除用户")
    @DeleteMapping("/{appId}/{openId}")
    public void delete(@ApiParam(value = "id", required = true) @PathVariable String appId,
            @ApiParam(value = "id", required = true) @PathVariable String openId) {
        getService().delete(appId, openId);
        operationLogApi.add("删除用户", UserContextHandler.getUserId(), appId, openId);
    }

    @ApiOperation("设置标签")
    @PostMapping("/{id}/setTags")
    @Transactional(rollbackFor = Exception.class)
    public void setTags(@ApiParam(value = "id", required = true) @PathVariable String id,
            @RequestBody SetTagRequestDTO request) {
        Collection<Long> tagIds = request.getTagIds();

        UserTagMapping deleteInfo = new UserTagMapping();
        deleteInfo.setOpenId(id);

        tagMappingService.delete(deleteInfo);

        if (!CollectionUtil.isEmpty(tagIds)) {
            Collection<UserTagMapping> mappings = tagIds.stream().map(tagId -> new UserTagMapping(id, tagId))
                    .collect(Collectors.toList());

            tagMappingService.replaceBatchInsert(mappings);
        }

        operationLogApi.add("设置标签", UserContextHandler.getUserId(), id, request);
    }

    @ApiOperation("批量设置标签")
    @PostMapping("/batchSetTags")
    public void batchSetTags(@RequestBody SetTagRequestDTO request) {
        Collection<Long> tagIds = request.getTagIds();
        Collection<String> openIds = request.getOpenIds();

        if (CollectionUtil.isEmpty(tagIds) || CollectionUtil.isEmpty(openIds)) {
            return;
        }

        Collection<UserTagMapping> mappings = new ArrayList<>(tagIds.size() * openIds.size());

        for (Long tagId : tagIds) {
            for (String openId : openIds) {
                mappings.add(new UserTagMapping(openId, tagId));
            }
        }

        tagMappingService.replaceBatchInsert(mappings);

        operationLogApi.add("批量设置标签", UserContextHandler.getUserId(), mappings);
    }

    @ApiOperation("导出Excel")
    @GetMapping("/exportExcel")
    public void exportExcel(HttpServletResponse response, WxUserSearchParams searchParams) {
        beforeFind(searchParams);
        ExcelUtils.exportExcel(response, getService().selectAll(searchParams), WxUserExcelExport.class,
                "WxUser-" + System.currentTimeMillis());

        operationLogApi.add("导出微信用户列表", UserContextHandler.getUserId(), searchParams);
    }

    @Autowired
    public void setTagService(UserTagService tagService) {
        this.tagService = tagService;
    }

    @Autowired
    public void setTagMappingService(UserTagMappingService tagMappingService) {
        this.tagMappingService = tagMappingService;
    }

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public void setOperationLogApi(OperationLogApi operationLogApi) {
        this.operationLogApi = operationLogApi;
    }
}
